import { KMap, KNumTable } from '@coldcloude/kai2';
import { compareZIndex, GridForm, KK_ZERO, KKObserver, KKP2D, KKP2DTable, KKStepAgent } from '@coldcloude/kakera';
import { CSC } from "./CivSimConstant";

export type LogicException = {
    code?: number,
    msg?: string
}

export const AT_CITY = 1;
export const AT_ARG = 2;
export const AT_IND = 3;
export const AT_MILI = 4;
export const AT_RESC = 4;

export const AM_NORMAL = 0;
export const AM_RESEARCH = 1;

export class CivSimEntity {
    belong: CivSimCiv = null;
    position = KK_ZERO;
    sameAs(entity:CivSimEntity){
        return compareZIndex(this.position,entity.position)===0;
    }
}

export class CivSimLand extends CivSimEntity {
    civilingMap = new KNumTable<number>();
    civiling = false;
}

export class CivSimArmy extends CivSimEntity {
    level = 0;
    amount = 0;
    movable = false;
    armyAttackable = false;
    cityAttackable = false;
    power(){
        return Math.round(CSC.army.power[this.level]*this.amount)|0;
    }
    afford(p:number){
        return Math.ceil(p/CSC.army.power[this.level])|0;
    }
}

export class CivSimArea extends CivSimEntity {
    type = 0;
    level = -1;
    targetLevel = 0;
    progress = 0;
    workerFrom:CivSimCity = null;
}

export class CivSimCity extends CivSimArea {
    popular = 1;
    grain = 0;
    wall = 0;
}

export class CivSimModeArea extends CivSimArea {
    mode = AM_NORMAL;
}

export class CivSimIndustryArea extends CivSimModeArea {
    
}

export class CivSimMilitaryArea extends CivSimModeArea {
    producting = false;
}

export class CivSimCiv {
    id = 0;
    name = "";
    landMap = new KKP2DTable<CivSimLand>();
    areaMap = new KKP2DTable<CivSimArea>();
    armyMap = new KKP2DTable<CivSimArmy>();
    cityMap = new KKP2DTable<CivSimCity>();
}

export class CivSimCivDetail extends CivSimCiv {
    //tech
    techPoint = 0;
    armyTechPoint = 0;
    ecoTechPoint = 0;
    //res
    gold = 0;
    //attribute
    sight = 0;
}

export type CivSimView = {
    controlCivs: CivSimCivDetail[],
    lastCiv: CivSimCivDetail,
    lastAction: CivSimAction,
    otherLandMap: KMap<KKP2D,CivSimLand>,
    otherAreaMap: KMap<KKP2D,CivSimArea>,
    otherArmyMap: KMap<KKP2D,CivSimArmy>
    otherCityMap: KMap<KKP2D,CivSimCity>,
}

export const CMD_TURN_PREPARE = -1;
export const CMD_TURN_END = 1;
export const CMD_POPULAR_UNALLOC_AREA = 11;
export const CMD_POPULAR_UNALLOC_CITY = 12;
export const CMD_POPULAR_ALLOC = 13;
export const CMD_AREA_BLD = 101;
export const CMD_AREA_SWITCH = 102;
export const CMD_AREA_RM = 103;
export const CMD_ARMY_PROD = 200;
export const CMD_ARMY_MOV = 201;
export const CMD_ARMY_ATK = 202;
export const CMD_ARMY_OCC = 203;
export const CMD_ARMY_BLD_CITY = 204;
export const CMD_MULTI = 999;

export const CMDS: number[] = [
    CMD_TURN_END,
    CMD_POPULAR_UNALLOC_AREA,
    CMD_POPULAR_UNALLOC_CITY,
    CMD_POPULAR_ALLOC,
    CMD_AREA_BLD,
    CMD_AREA_RM,
    CMD_AREA_SWITCH,
    CMD_ARMY_PROD,
    CMD_ARMY_MOV,
    CMD_ARMY_ATK,
    CMD_ARMY_OCC,
    CMD_ARMY_BLD_CITY,
    CMD_MULTI
];

export class CivSimAction {
    command: number
    constructor(command:number){
        this.command = command;
    }
}

export class CivSimActionMulti extends CivSimAction {
    actions:CivSimAction[]
    constructor(actions?:CivSimAction[]){
        super(CMD_MULTI);
        this.actions = actions?actions:[];
    }
}

export const ACT_TURN_PREPARE = new CivSimAction(CMD_TURN_PREPARE);
export const ACT_TURN_END = new CivSimAction(CMD_TURN_END);

export class CivSimActionSource extends CivSimAction {
    source: KKP2D
    constructor(command:number,source:KKP2D){
        super(command);
        this.source = source;
    }
}

export class CivSimActionSourceTarget extends CivSimActionSource {
    target: KKP2D
    constructor(command:number,source:KKP2D,target:KKP2D){
        super(command,source);
        this.target = target;
    }
}

export class CivSimActionPopularUnallocArea extends CivSimActionSource {
    constructor(source:KKP2D){
        super(CMD_POPULAR_UNALLOC_AREA,source);
   }
}

export class CivSimActionPopularUnallocCity extends CivSimActionSource {
    constructor(source:KKP2D){
        super(CMD_POPULAR_UNALLOC_CITY,source);
    }
}

export class CivSimActionPopularAlloc extends CivSimActionSourceTarget {
    constructor(source:KKP2D,target:KKP2D){
        super(CMD_POPULAR_ALLOC,source,target);
    }
}

export class CivSimActionAreaBuild extends CivSimActionSource {
    type:number;
    constructor(source:KKP2D,type:number){
        super(CMD_AREA_BLD,source);
        this.type = type;
    }
}

export class CivSimActionAreaSwitch extends CivSimActionSource {
    mode:number;
    constructor(source:KKP2D,mode:number){
        super(CMD_AREA_SWITCH,source);
        this.mode = mode;
    }
}

export class CivSimActionAreaRemove extends CivSimActionSource {
    delta:number;
    constructor(source:KKP2D,delta:number){
        super(CMD_AREA_RM,source);
        this.delta = delta;
    }
}

export class CivSimActionArmyProduct extends CivSimActionSource {
    constructor(source:KKP2D){
        super(CMD_ARMY_PROD,source);
    }
}

export class CivSimActionArmyMove extends CivSimActionSourceTarget {
    constructor(source:KKP2D,target:KKP2D){
        super(CMD_ARMY_MOV,source,target);
    }
}

export class CivSimActionArmyAttack extends CivSimActionSourceTarget {
    constructor(source:KKP2D,target:KKP2D){
        super(CMD_ARMY_ATK,source,target);
    }
}

export class CivSimActionArmyOccupy extends CivSimActionSource {
    constructor(source:KKP2D){
        super(CMD_ARMY_OCC,source);
    }
}

export class CivSimActionArmyBuildCity extends CivSimActionSource {
    constructor(source:KKP2D){
        super(CMD_ARMY_BLD_CITY,source);
    }
}

export interface CivSimGridAware {
    setGridForm(gridForm:GridForm):void;
}

export interface CivSimAgent extends KKStepAgent<number,CivSimAction>,CivSimGridAware {
    getControlId():number;
}

export interface CivSimObserver extends KKObserver<CivSimView>,CivSimGridAware {
    getObservedIds():number[];
}

export function calcTechLevel(civ:CivSimCivDetail,isEco:boolean){
    const tech = civ.techPoint+(isEco?civ.ecoTechPoint:civ.armyTechPoint);
    let l = 0;
    for(const th of CSC.tech.threshold){
        if(tech>=th){
            l++;
        }
    }
    return l;
}

export function calcPopularCost(area:CivSimArea){
    let pcc = null;
    switch(area.type){
        case AT_ARG:
            pcc = CSC.area.popularCost.agriculture;
            break;
        case AT_IND:
            pcc = CSC.area.popularCost.industry;
            break;
        case AT_RESC:
            pcc = CSC.area.popularCost.research;
            break;
        case AT_MILI:
            pcc = CSC.area.popularCost.militery;
            break;
        case AT_CITY:
            pcc = CSC.area.popularCost.city;
        default:
            return 1;
    }
    const lv = area.level;
    return lv>=0&&lv<pcc.length?pcc[lv]:0;
}
